﻿/**
 @file Stmt.cpp
 @brief CLite_Stmt 소스 파일.
*/

#include "StdAfx.h"
#include "Lite_Stmt.h"
#include "Lite_Dbc.h"
#include <stdlib.h>

/**
 @brief 기본 생성자로서, 자신의 인덱스와 DBC를 저장하고

 기타 필요한 초기화를 수행 한다.
*/

CLite_Stmt::CLite_Stmt(const int nMyIndex,  /**< 배열상의 자신의 순번. */
	         CLite_Dbc * pDbc,         /**< DBC 포인터 */
			 PACKET_STRT *  pPack /**< 패킷의 포인터 */)
{
	m_nMyIndex = nMyIndex;
	m_pDbc = pDbc;
	m_pPack = pPack;
	m_bUse = TRUE;
}

/**
 @brief 기본 소멸자로서, 생성된 자원을 해제 한다.
*/
CLite_Stmt::~CLite_Stmt()
{
}

/**
 @brief 현재 사용 유무를 나타낸다.
 이 플래그는 STMT 객체가 파괴되지 않은 상태에서 사용될수 있는 상태를 나타낸다. 
*/
BOOL CLite_Stmt::IsUsed()
{
	return m_bUse;
}

/**
 @brief 현재 사용 유무를 나타낸다.
 이 플래그는 STMT 객체가 파괴되지 않은 상태에서 사용될수 있는 상태를 나타낸다. 
*/
void CLite_Stmt::SetUsed()
{
	m_bUse = TRUE;
}
/**
 @brief 현재 사용에 대한 플래그를 Off시킨다.
 이 객체는 사용되지 않으므로, 이 객체를 사용할 수 있다는 뜻이 된다.
*/
void CLite_Stmt::CloseStmt()
{
	m_bUse = FALSE;
}

/**
 @brief SQL문중 레코드셋 리턴이 필요 있는 SQL문 실행.
*/
BOOL CLite_Stmt::Prepare(const char * pszSQL)
{
	//==================================================
	/// [1] SQL문 크기 검사.
	//==================================================
	if ( 0 >= strlen(pszSQL))
	{
		return FALSE;
	}
	//==================================================
	/// [2] 관련 변수 초기화 및 설정.
	//==================================================
	int nRemain = strlen(pszSQL);          ///< SQL문 전송후에 남은 SQL문.
	int	nPos = 0;             ///< SQL문 중에서 보낼 마지막 위치.
	int	nReply = REPLY_SERVER_INITIAL;           ///< 서버의 응답 코드 저장.
	short nStat ;            ///< 현재 상태 코드 저장.

	BOOL  bNew = TRUE;
	m_bFetchStatEnd = FALSE; 
	m_nColCount = 0;
	int nSize = 0;
	//==================================================
	/// [3] SQL문 전송.
	//==================================================
	while(nRemain > 0 )
	{
		if( nRemain <= DATA_SIZE )
		{
			nStat = STAT_END;
			nSize = nRemain;
		}
		else if ( TRUE == bNew)
		{
			nStat = STAT_START;
			nSize = DATA_SIZE;
		}
		else
		{
			nStat = STAT_CONTINUE;
			nSize = DATA_SIZE;
		}
		
		if ( FALSE == m_pDbc->WriteReadSock(m_nMyIndex, ITEM_SELECT, nStat, nReply,nSize, pszSQL + nPos))
		{
			m_pDbc->SetErr(m_pPack->szData);
			return FALSE;
		}
		nPos += nSize;
		nRemain -= DATA_SIZE;		
		bNew = FALSE;
		nReply = REPLY_SERVER_OK;
	}
	//==================================================
	/// [5] 컬럼 숫자 설정.
	//==================================================
	m_nColCount = GetFieldCount();
	//==================================================
	/// [8] 받기 준비 받기 변수들 초기화.
	//==================================================
	m_nGetValIdx = 0; 
	FetchProcess();
	return TRUE;
}

/**
 @brief 서버로부터 현재 Query된 컬럼의 숫자를 가져 온다.
*/
short CLite_Stmt::GetFieldCount()
{
	if(FALSE == m_pDbc->WriteReadSock(m_nMyIndex ,ITEM_COLUMNCOUNT, STAT_END, REPLY_SERVER_INITIAL,strlen("FIELD_COUNT"),
		"FIELD_COUNT"))
	{
		return 0;
	}
	short nCol = 0;
	memcpy(&nCol,m_pPack->szData,sizeof(short));
	return nCol;
}

/**
 @brief 서버로부터 컬럼 정보를 가져 온다.
*/
void CLite_Stmt::GetColumnInfo(const short nIndex,COLUMN_INFO * pColumn)
{
	if (( nIndex >= 0 ) && ( nIndex < m_nColCount))
	{
		char szData[10];
		memset(szData,'\0',10);
		szData[0] = (char)nIndex;
		if( TRUE == m_pDbc->WriteReadSock(m_nMyIndex, ITEM_COLUMNINFO,STAT_END,REPLY_SERVER_OK,sizeof(short),
			szData))
		{
			memset(pColumn,0,sizeof(COLUMN_INFO));
			memcpy(pColumn,m_pPack->szData,sizeof(COLUMN_INFO));
		}
	}
}

/**
 @brief 실제로 통신을 하여서 컬럼의 이름을 리턴한다.
 @return 컬럼 이름 포인터 리턴.
*/
const char * CLite_Stmt::GetColName(const short nIndex)
{
	if (( nIndex >= 0 ) && ( nIndex < m_nColCount))
	{
		char szData[10];
		memset(szData,'\0',10);
		szData[0] = (char)nIndex;
		if( TRUE == m_pDbc->WriteReadSock(m_nMyIndex,ITEM_COLUMNNAME,STAT_END,REPLY_SERVER_OK,sizeof(short),szData))
		{
			return m_pPack->szData;
		}
	}
	return NULL;
}

/**
 @brief 실제로 통신을 하여서 데이터를 가져오는 프로세스.
*/
void CLite_Stmt::FetchProcess()
{
	m_nfetchPos = 0;
	int nReply = REPLY_SERVER_INITIAL;
	if(FALSE== m_pDbc->WriteReadSock(m_nMyIndex,ITEM_FETCH, STAT_END, REPLY_SERVER_OK,strlen("DATA_FETCH"),"DATA_FETCH"))
	{
		m_bIsEnd = TRUE;                              // 데이터의 끝이다.
		m_bFetchStatEnd = TRUE;                       // Fetch의 끝이다.
		memset(&m_fetchPack,0 ,sizeof(PACKET_STRT )); // 어떤 데이터도 없다.
		return;
	}
	if( REPLY_CLIENT_NOTEND == m_pPack->nReply)
	{
		m_bIsEnd = FALSE;
	}
	else
	{
		m_bIsEnd = TRUE;
	}
	switch(m_pPack->nStat)
	{
	case STAT_END:
		m_bFetchStatEnd = TRUE;
		break;
	case STAT_CONTINUE:
		m_bFetchStatEnd = FALSE;
		break;
	}
	memcpy(&m_fetchPack,m_pPack,sizeof(PACKET_STRT));
}

/**
 @brief 다음 레코드 셋으로 이동 한다.
*/
BOOL CLite_Stmt::Step()
{
	//==================================================
	/// [1] 컬럼을 가르키는 인덱스를 0으로 한다.
	//==================================================
	m_nGetValIdx = 0;
	//==================================================
	/// [2] 데이터를 모두 소비 했는지 알아낸다.
	//==================================================
	if((m_nfetchPos >= m_fetchPack.nDataLen) &&	(TRUE == m_bIsEnd) && ( TRUE ==  m_bFetchStatEnd))
	{
		return FALSE;
	}
	else
	{
		return TRUE;
	}
}

/**
 @brief 현재의 컬럼의 값을 가져온다.
*/
const char * CLite_Stmt::GetValue()
{
	//==================================================
	/// [1] 컬럼인덱스 체크.
	//==================================================
	if( m_nGetValIdx >= m_nColCount)
		return NULL;
	memset(m_szValue, '\0', 4097);
	int nPos = 0;
	//==================================================
	/// [2] 데이터를 소비한다.
	//==================================================
	while(nPos < 4097)
	{
		while( m_nfetchPos < m_fetchPack.nDataLen)
		{
			if( '\0' == m_fetchPack.szData[m_nfetchPos] )
			{
				m_nfetchPos ++;
				m_nGetValIdx ++;
				return (const char *)(m_szValue+1);
			}
			else
			{
				m_szValue[nPos] = m_fetchPack.szData[m_nfetchPos];
				nPos ++;
				m_nfetchPos ++;
			}
		}
		FetchProcess();
	}
	return (const char *)(m_szValue+1);
}

const char * CLite_Stmt::GetValueBuf()
{
	GetValue();
	return (const char *)m_szValue;
}

/**
 @brief 에러 메시지를 설정 한다. 모든 에러 메시지는 이 함수를 사용하여 설정 한다.
*/
void CLite_Stmt::SetErr(const char * pErr)
{
	memset(m_szErr,0,50);
	STRCPY(m_szErr,pErr,50);
}

/**
 @brief 에러 메시지를 설정 리턴 한다.
*/
const char * CLite_Stmt::GetErr()
{
	return m_szErr;
}
